package com.xinqi.modules.homework.homework.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xinqi.common.base.enums.YesNoEnum;
import com.xinqi.common.base.enums.YesNoNumberEnum;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.base.response.Param;
import com.xinqi.common.base.response.R;
import com.xinqi.common.base.utils.spring.Spring;
import com.xinqi.common.core.enums.*;
import com.xinqi.common.core.utils.MessageUtils;
import com.xinqi.common.mybatis.data.service.impl.BaseServiceImpl;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.common.satoken.utils.LoginHelper;
import com.xinqi.modules.course.chapter.dto.client.CourseChapterClient;
import com.xinqi.modules.course.classmenu.client.ClassMenuClient;
import com.xinqi.modules.course.clazz.client.ClassGroupClient;
import com.xinqi.modules.course.clazz.client.ClassGroupStudentClient;
import com.xinqi.modules.course.clazz.client.ClassStudentClient;
import com.xinqi.modules.course.clazz.dto.rsp.ClassGroupResultDTO;
import com.xinqi.modules.course.clazz.dto.rsp.ClassGroupStudentResultDTO;
import com.xinqi.modules.course.clazz.dto.rsp.ClassStudentResultDTO;
import com.xinqi.modules.course.content.dto.client.CourseContentClient;
import com.xinqi.modules.course.content.dto.req.CourseContentCreateDTO;
import com.xinqi.modules.course.content.dto.req.CourseContentUpdateDTO;
import com.xinqi.modules.course.content.dto.rsp.CourseContentResultDTO;
import com.xinqi.modules.homework.homework.assistant.AssistantListen;
import com.xinqi.modules.homework.homework.convert.CourseHomeworkConvert;
import com.xinqi.modules.homework.homework.domain.CourseHomeworkEntity;
import com.xinqi.modules.homework.homework.dto.req.*;
import com.xinqi.modules.homework.homework.dto.rsp.CourseHomeworkResultDTO;
import com.xinqi.modules.homework.homework.dto.rsp.CourseHomeworkStudentInfoResultDTO;
import com.xinqi.modules.homework.homework.mapper.CourseHomeworkMapper;
import com.xinqi.modules.homework.homework.service.CourseHomeworkService;
import com.xinqi.modules.homework.homework.service.CourseHomeworkStudentLogService;
import com.xinqi.modules.homework.homework.utils.MathUtils;
import com.xinqi.modules.stats.assistant.dto.rsp.AssistantTotalResultDTO;
import com.xinqi.modules.stats.assistant.dto.rsp.StudentInfoResultDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.Objects.nonNull;

/**
 * 课程作业配置表服务层实现
 *
 * @author: system
 * @date: 2023/03/08
 */
@Service("courseHomeworkService")
@RequiredArgsConstructor
@Slf4j
public class CourseHomeworkServiceImpl extends BaseServiceImpl<CourseHomeworkMapper, CourseHomeworkEntity> implements CourseHomeworkService {

    private final CourseHomeworkConvert courseHomeworkConvert;

    private final CourseHomeworkStudentLogService courseHomeworkStudentLogService;

    private final CourseContentClient courseContentClient;

    private final ClassMenuClient classMenuClient;
    private final CourseChapterClient courseChapterClient;
    private final ClassStudentClient classStudentClient;
    private final ClassGroupClient classGroupClient;
    private final ClassGroupStudentClient classGroupStudentClient;

    private final AssistantListen assistantListen;


    /**
     * 查询 课程栏目作业-分页-未发布
     */
    @Override
    @DS("slaver")
    public PageInfo<CourseHomeworkResultDTO> pageNoRelease(Param pageable, CourseHomeworkQueryDTO query) {
        Long userId = LoginHelper.getUserId();
        ClassStudentResultDTO teacher = R.as(classStudentClient.findByStudentId(query.getClassId(), userId));
        if (!Objects.equals(ClassRoleEnum.TEACHER.getCode(), teacher.getClassRole()) && !Objects.equals(ClassRoleEnum.ASSISTANT.getCode(), teacher.getClassRole())) {
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("course.notice.is.not.teacher"));
        }
        IPage<CourseHomeworkResultDTO> page = this.baseMapper.homeworkInfoListNoRelease(Pages.page(pageable), query);
        return Pages.convert(page, courseHomeworkConvert::convert);
    }

    /**
     * 查询 课程栏目作业-分页-已发布
     */
    @Override
    @DS("slaver")
    public PageInfo<CourseHomeworkResultDTO> pageRelease(Param pageable, CourseHomeworkQueryDTO query) {
        Long userId = LoginHelper.getUserId();
        ClassStudentResultDTO teacher = R.as(classStudentClient.findByStudentId(query.getClassId(), userId));
        if (!Objects.equals(ClassRoleEnum.TEACHER.getCode(), teacher.getClassRole()) && !Objects.equals(ClassRoleEnum.ASSISTANT.getCode(), teacher.getClassRole())) {
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("course.notice.is.not.teacher"));
        }
        IPage<CourseHomeworkResultDTO> page = this.baseMapper.homeworkInfoListRelease(Pages.page(pageable), query);
        return Pages.convert(page, courseHomeworkConvert::convert);
    }

    /**
     * 查询 课程栏目作业-分页
     */
    @Override
    @DS("slaver")
    public PageInfo<CourseHomeworkResultDTO> page(Param pageable, CourseHomeworkQueryDTO query) {
        CommonErrors.BAD_REQUEST.check(query.getClassId() != null, MessageUtils.message("course.content.classId.not.blank"));
        pageable.setOrderByColumn("releaseTime");
        pageable.setIsAsc("desc");
        LambdaQueryWrapper<CourseHomeworkEntity> wrapper = Queries.lambda();
        Queries.accept(query.getClassId(), v -> wrapper.eq(CourseHomeworkEntity::getClassId, v));
        return this.baseMapper.selectDtoPageInfo(Pages.page(pageable), wrapper(query), courseHomeworkConvert::convert);
    }

    /**
     * 查询 查询课程栏目作业
     */
    @Override
    public List<CourseHomeworkResultDTO> find(CourseHomeworkQueryDTO query) {
        return this.baseMapper.selectDtoList(wrapper(query), courseHomeworkConvert::convert);
    }

    private LambdaQueryWrapper<CourseHomeworkEntity> wrapper(CourseHomeworkQueryDTO query) {
        LambdaQueryWrapper<CourseHomeworkEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(CourseHomeworkEntity::getId, v));
        Queries.accept(HomeWorkStatusEnum.IS_DELETE.getCode(), v -> wrapper.eq(CourseHomeworkEntity::getIsDelete, v));
        Queries.accept(query.getTiming(), v -> wrapper.eq(CourseHomeworkEntity::getTiming, v));
        Queries.accept(query.getStatus(), v -> wrapper.eq(CourseHomeworkEntity::getStatus, v));
        return wrapper;
    }

    /**
     * 查询课程栏目作业-详情根据ID
     */
    @Override
    public CourseHomeworkResultDTO findById(Long id, CourseHomeworkStudentDetailDTO dto) {

        // 获取作业详情数据
        CommonErrors.BAD_REQUEST.check(nonNull(id), MessageUtils.message("course.homework.id.not.blank"));
        CourseHomeworkResultDTO result = this.baseMapper.findDetailById(id, dto);
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(result), MessageUtils.message("course.homework.id.not.exit"));

        // 格式化分数
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(result), MessageUtils.message("course.homework.not.blank"));
        result.setScore(MathUtils.stripTrailingZeros(result.getScore(), 1));

        if (Objects.nonNull(result.getChapterId())) {
            result.setChapterName(R.as(courseChapterClient.selectName(result.getChapterId())));
        }

        //获取小组信息
        if (Objects.equals(HomeWorkTypeEnum.TASK_GROUP.getCode(), result.getTaskType())) {
            List<Long> groupIds = Arrays.stream(result.getGroupIds().split(",")).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
            // 获取选中的小组
            List<ClassGroupResultDTO> groups = R.as(classGroupClient.selectList(groupIds));
            // 校验小组是否被删除
            groupIds.forEach(item -> {
                ClassGroupResultDTO group = groups.stream().filter(v -> Objects.equals(item, v.getId())).findFirst().orElse(null);
                if (Objects.nonNull(group)) {
                    result.setGroupPid(group.getPid());
                    result.setGroupNames(result.getGroupNames() == null ? group.getName() : result.getGroupNames() + "," + group.getName());
                } else {
                    result.setGroupPid(0L);
                    result.setGroupNames(result.getGroupNames() == null ? "小组已删除" : result.getGroupNames() + "," + "小组已删除");
                }
            });
        }

        // 设置状态
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), result.getStatus())) {
            if (result.getEndTime().isBefore(LocalDateTime.now())) {
                result.setStatus(HomeWorkStatusEnum.CLOSED.getCode());
            } else {
                result.setStatus(HomeWorkStatusEnum.IN_PROGRESS.getCode());
            }
        } else {
            if (Objects.equals(YesNoNumberEnum.YES.getCode(), result.getTiming())) {
                result.setStatus(HomeWorkStatusEnum.SCHEDULED_RELEASE.getCode());
            } else {
                result.setStatus(HomeWorkStatusEnum.UNPUBLISHED.getCode());
            }
        }

        // 判断是否查询学生信息
        if (Objects.nonNull(dto.getStudentId())) {
            // 获取主学生信息
            ClassStudentResultDTO mainStudent = R.as(classStudentClient.findVirtualClassStudentByClassIdAndUserId(result.getClassId(), dto.getStudentId()));
            if (Objects.nonNull(mainStudent)) {
                dto.setStudentId(mainStudent.getStudentId());
            }

            CourseHomeworkStudentLogQueryDTO queryDTO = new CourseHomeworkStudentLogQueryDTO();
            queryDTO.setClassId(result.getClassId());
            queryDTO.setContentId(id);
            queryDTO.setTimes(dto.getTimes() == null ? result.getRepeatedDay() : dto.getTimes());
            queryDTO.setStudentId(dto.getStudentId());
            CourseHomeworkStudentInfoResultDTO info = courseHomeworkStudentLogService.findByParam(queryDTO);
            result.setTaskStatus(Objects.nonNull(info) ? info.getTaskStatus() : HomeWorkStudentStatusEnum.NOT_SUBMIT.getCode());
        } else {
            // 不是学生默认传已批
            result.setTaskStatus(HomeWorkStudentStatusEnum.APPROVED.getCode());
        }

        //已分享数量
        CourseHomeworkStudentLogQueryDTO logQueryDTO = new CourseHomeworkStudentLogQueryDTO();
        logQueryDTO.setContentId(id);
        logQueryDTO.setTimes(dto.getTimes());
        logQueryDTO.setShare(YesNoEnum.YES.ordinal());
        result.setSharedCount(courseHomeworkStudentLogService.findSharedCount(logQueryDTO, result.getTaskStatus()));
        return result;
    }

    @Override
    public CourseHomeworkResultDTO findSimpleById(Long id) {
        return this.baseMapper.selectDtoById(id, courseHomeworkConvert::convert);
    }

    /**
     * 新增课程，同时生成好几轮的作业
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertBath(CourseHomeworkCreateDTO dto) {
        this.checkInsertParam(dto);

        List<CourseHomeworkEntity> homeworkEntityList = new ArrayList<>();
        CourseHomeworkEntity entity = courseHomeworkConvert.create(dto);

        //添加当前作业
        this.addCurrentHomework(homeworkEntityList, entity);

        //添加其他班级
        List<CourseHomeworkEntity> otherClassHomeworkList = this.addOtherClassHomework(dto.getStatus(), homeworkEntityList);
        if (CollectionUtils.isNotEmpty(otherClassHomeworkList)) {
            homeworkEntityList.addAll(otherClassHomeworkList);
        }

        //保存
        this.saveBatch(homeworkEntityList, 1500);

        // 立即发布,同步到学生的逻辑
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), dto.getNowRelease())) {
            this.executeHomeworkList(dto.getStatus(), dto.getTaskType(), homeworkEntityList);
        }
        return true;
    }

    private List<CourseHomeworkEntity> addOtherClassHomework(Integer status, List<CourseHomeworkEntity> homeworkList) {
        List<CourseHomeworkEntity> otherClassHomeWorkEntityList = new ArrayList<>();
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), status)) {
            homeworkList.forEach(entity -> {
                //设置多班级作业
                this.addOtherClassHomeworkEntityList(entity, otherClassHomeWorkEntityList);
            });
        }

        return otherClassHomeWorkEntityList;

    }

    /**
     * 生成多轮次的作业，这里并不存库
     *
     * @param entity
     * @return
     */
    @Override
    public void addRepeatHomeworkList(List<CourseHomeworkEntity> homeworkEntityList, CourseHomeworkEntity entity) {
        //只有发布的时候和定时发布触发的时候才添加多轮次作业
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), entity.getNowRelease()) || Objects.equals(YesNoNumberEnum.YES.getCode(), entity.getTiming())) {
            entity.setStatus(YesNoNumberEnum.YES.getCode());
            if (Objects.equals(YesNoEnum.YES.ordinal(), entity.getIsRepeat()) && entity.getRepeatDay() > YesNoEnum.YES.ordinal()) {
                this.addRepeatList(homeworkEntityList, entity);
            }
        }
    }

    private void addCurrentHomework(List<CourseHomeworkEntity> homeworkEntityList, CourseHomeworkEntity entity) {
        long batchNum = System.currentTimeMillis();
        entity.setCurrRepeatDay(1);
        entity.setRepeatedDay(1);
        entity.setBatchNum(batchNum);
        homeworkEntityList.add(entity);
    }

    /**
     * 这里会模拟出多个轮次的作业实体，作业id和第一轮的作业id是一样的，但并不会保存到数据库
     *
     * @param homeworkEntityList
     * @param entity
     */
    private void addRepeatList(List<CourseHomeworkEntity> homeworkEntityList, CourseHomeworkEntity entity) {
        for (int i = 1; i < entity.getRepeatDay(); i++) {
            CourseHomeworkEntity repeatEntity = courseHomeworkConvert.newEntity(entity);
            repeatEntity.setId(entity.getId());
            repeatEntity.setStatus(YesNoNumberEnum.YES.getCode());
            repeatEntity.setBatchNum(entity.getBatchNum());
            repeatEntity.setRepeatedDay(i + 1);
            repeatEntity.setCurrRepeatDay(i + 1);
            homeworkEntityList.add(repeatEntity);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean executeHomeworkList(Integer status, Integer taskType, List<CourseHomeworkEntity> homeworkEntityList) {
        // 已发布同步操作
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), status)) {
            // 同步到课程内容汇总表(预留同步班级异步时间放在最后执行)
            this.syncContentHomework(homeworkEntityList.stream().map(courseHomeworkConvert::convert).collect(Collectors.toList()));

            // 同步学生作业数据
            this.initStudentLogBatch(homeworkEntityList, status, taskType);

            // 根据 id 进行分组并去重，多轮次作业只发一次
            List<CourseHomeworkEntity> uniqueHomeworkList = new ArrayList<>(homeworkEntityList.stream().collect(Collectors.toMap(CourseHomeworkEntity::getId,
                    Function.identity(), (existing, replacement) -> existing)).values());
            Spring.committed(() -> uniqueHomeworkList.forEach(homeworkEntity -> assistantListen.releaseCourseContent(homeworkEntity.getId(), AssistantMessageTypeEnum.HOMEWORK)));
        }

        return true;
    }

    private void addOtherClassHomeworkEntityList(CourseHomeworkEntity entity, List<CourseHomeworkEntity> homeworkEntityList) {
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), entity.getSynchro()) && StringUtils.isNotEmpty(entity.getClassIds())) {
            String[] classIds = entity.getClassIds().split(",");
            for (String classId : classIds) {
                CourseHomeworkEntity newEntity = courseHomeworkConvert.newEntity(entity);
                newEntity.setClassId(Long.parseLong(classId));
                newEntity.setSynchro(0);
                newEntity.setClassIds(null);
                newEntity.setChapterId(null);
                newEntity.setId(null);
                homeworkEntityList.add(newEntity);
            }
        }
    }

    private void checkInsertParam(CourseHomeworkCreateDTO dto) {
        // 校验用户角色
        List<ClassRoleEnum> classRoles = new ArrayList<>();
        classRoles.add(ClassRoleEnum.TEACHER);
        classRoles.add(ClassRoleEnum.ASSISTANT);
        classStudentClient.checkRole(dto.getClassId(), LoginHelper.getUserId(), classRoles);
        // 定时发布 时间判断
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), dto.getTiming())) {
            CommonErrors.BAD_REQUEST.check(nonNull(dto.getReleaseTime()), MessageUtils.message("course.content.select.releasetime"));
        }
        // 小组作业 小组判断
        if (Objects.equals(HomeWorkTypeEnum.TASK_GROUP.getCode(), dto.getTaskType())) {
            CommonErrors.BAD_REQUEST.check(nonNull(dto.getGroupIds()), MessageUtils.message("course.homework.select.publish.to"));
            List<Long> groupList = Arrays.stream(dto.getGroupIds().split(",")).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
            List<ClassGroupStudentResultDTO> studentList = R.as(classGroupStudentClient.findStudentListByGroupIds(groupList));
            CommonErrors.BAD_REQUEST.check(CollectionUtil.isNotEmpty(studentList), "小组暂无成员");
        }

        // 判断作业发布状态(未发布作业轮数不做更新 1未发布 2定时发布 3进行中 4已结束 5未开始)
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), dto.getNowRelease())) {
            dto.setStatus(YesNoNumberEnum.YES.getCode());
            dto.setReleaseTime(LocalDateTime.now());
        } else if (Objects.equals(YesNoNumberEnum.NO.getCode(), dto.getNowRelease()) && Objects.equals(YesNoNumberEnum.YES.getCode(), dto.getTiming())) {
            CommonErrors.BAD_REQUEST.check(dto.getReleaseTime() != null, MessageUtils.message("course.content.releasetime.not.blank"));
            CommonErrors.BAD_REQUEST.check(dto.getReleaseTime().isAfter(LocalDateTime.now()), MessageUtils.message("course.content.now.before.releasetime"));
            dto.setStatus(YesNoNumberEnum.NO.getCode());
        } else {
            dto.setStatus(YesNoNumberEnum.NO.getCode());
            dto.setReleaseTime(null);
        }
        // 判断是否 打卡作业 非打卡作业默认 1
        if (Objects.equals(dto.getIsRepeat(), YesNoNumberEnum.NO.getCode())) {
            dto.setRepeatDay(1);
            //多轮次作业需要校验结束时间
        } else {
            LocalDateTime publishTime;
            //定时发布的作业开始时间取发布时间
            if (Objects.equals(YesNoEnum.YES.ordinal(), dto.getTiming())) {
                publishTime = dto.getReleaseTime();
            } else {
                //立即发布的作业，不管是否发布，开始时间都按当前时间算
                publishTime = LocalDateTime.now();
            }
            // 计算日期差异
            long daysDifference = ChronoUnit.DAYS.between(publishTime, dto.getEndTime());
            CommonErrors.BAD_REQUEST.check(daysDifference >= dto.getRepeatDay(), "作业轮数必须小于作业期限");
        }

        CommonErrors.BAD_REQUEST.check(dto.getRepeatDay() != null, MessageUtils.message("course.homework.times.is.not.blank"));
    }

    /**
     * 初始化学生作业记录
     */
    @Override
    public void initStudentLog(CourseHomeworkEntity entity) {
        // 判断作业是否未发布 未发布不更新作业轮数表
        if (entity.getStatus().equals(YesNoNumberEnum.YES.getCode())) {
            CourseHomeworkStudentLogCreateDTO studentLogCreateDTO = new CourseHomeworkStudentLogCreateDTO();
            studentLogCreateDTO.setContentId(entity.getId());
            studentLogCreateDTO.setClassId(entity.getClassId());
            for (int i = 0; i < entity.getRepeatDay(); i++) {
                studentLogCreateDTO.setTimes(i + 1);
                if (Objects.equals(entity.getTaskType(), HomeWorkTypeEnum.TASK_PERSONAL.getCode())) {
                    // 个人作业
                    courseHomeworkStudentLogService.syncStudent(studentLogCreateDTO);
                } else {
                    // 小组作业
                    courseHomeworkStudentLogService.syncGroupStudent(studentLogCreateDTO, entity.getGroupIds());
                }
            }
        }
    }

    /**
     * 初始化学生作业记录，发布的时候才更新这个
     */
    @Override
    public void initStudentLogBatch(List<CourseHomeworkEntity> homeworkEntityList, Integer status, Integer taskType) {
        // 判断作业是否未发布 未发布不更新作业轮数表
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), status)) {
            if (Objects.equals(HomeWorkTypeEnum.TASK_PERSONAL.getCode(), taskType)) {
                // 个人作业
                courseHomeworkStudentLogService.insertClassStudentLogBatch(homeworkEntityList);
            } else {
                // 小组作业
                courseHomeworkStudentLogService.insertGroupStudentLogBatch(homeworkEntityList);
            }
        }
    }


    /**
     * 作业同步到课程内容汇总表
     */
    @Override
    public void syncContentHomework(List<CourseHomeworkResultDTO> list) {
        List<CourseContentCreateDTO> contentList = list.stream().map(item -> {
            CourseContentCreateDTO create = new CourseContentCreateDTO();
            create.setUserId(item.getUserId());
            create.setContentId(item.getId());
            create.setTitle(item.getTitle());
            create.setContent(item.getContent());
            create.setType(CourseContentTypeEnum.HOMEWORK.getCode());
            create.setClassId(item.getClassId());
            create.setChapterId(item.getChapterId());
            create.setStatus(YesNoNumberEnum.YES.getCode());
            create.setReleaseTime(item.getReleaseTime());
            create.setEndTime(item.getEndTime());
            create.setTaskType(item.getTaskType());
            return create;
        }).collect(Collectors.toList());
        // 查询是否已存在
        List<Long> ids = list.stream().map(CourseHomeworkResultDTO::getId).collect(Collectors.toList());
        List<CourseContentResultDTO> contentResultList = R.as(courseContentClient.findContentList(ids));

        // 定义更新和添加的List
        List<CourseContentCreateDTO> insertList;
        List<CourseContentUpdateDTO> updateList = new ArrayList<>();
        if (Objects.nonNull(contentResultList) && contentResultList.size() > 0) {
            insertList = contentList.stream().filter(item ->
                    contentResultList.stream().noneMatch(each -> Objects.equals(item.getContentId(), each.getContentId()))
            ).collect(Collectors.toList());

            // 删选更新的内容
            updateList = contentList.stream().filter(item ->
                    contentResultList.stream().allMatch(each -> Objects.equals(item.getContentId(), each.getContentId()))
            ).map(item -> {
                CourseContentUpdateDTO update = new CourseContentUpdateDTO();
                update.setUserId(item.getUserId());
                update.setContent(item.getContent());
                update.setTitle(item.getTitle());
                update.setType(CourseContentTypeEnum.HOMEWORK.getCode());
                update.setClassId(item.getClassId());
                update.setChapterId(item.getChapterId());
                update.setStatus(YesNoNumberEnum.YES.getCode());
                update.setReleaseTime(item.getReleaseTime());
                update.setEndTime(item.getEndTime());
                return update;
            }).collect(Collectors.toList());

            // 更新内容添设置主键
            updateList.forEach(item -> contentResultList.forEach(each -> {
                if (Objects.equals(item.getContentId(), each.getContentId())) {
                    item.setId(each.getId());
                }
            }));
        } else {
            insertList = new ArrayList<>(contentList);
        }
        // 新增内容
        if (insertList.size() > 0) {
            courseContentClient.saveBatchContent(insertList);
        }
        // 更新内容
        if (updateList.size() > 0) {
            courseContentClient.updateBatch(updateList);
        }
    }

    /**
     * 根据id修改 课程栏目作业数据，这里包括：发布状态的更新和未发布状态的更新，
     * 未发布状态可以立即发布，
     * 已发布和未发布均不能修改作业轮数，已发布只能修改作业的结束时间。
     */

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(CourseHomeworkUpdateDTO dto) {
        CourseHomeworkEntity old = Optional.ofNullable(this.getById(dto.getId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("data.does.not.exist")));

        //已发布编辑
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), old.getStatus())) {
            CourseHomeworkEntity updateEntity = new CourseHomeworkEntity();
            updateEntity.setId(old.getId());
            updateEntity.setGroupIds(old.getGroupIds());
            if (old.getEndTime().isBefore(LocalDateTime.now())) {
                CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("course.homework.end.valid"));
                updateEntity.setEndTime(dto.getEndTime());
            }
            if (Objects.nonNull(dto.getChapterId())) {
                updateEntity.setChapterId(dto.getChapterId());
            }
            this.updateById(updateEntity);
            //未发布编辑,可以选择立即发布
        } else {
            if (Objects.isNull(dto.getChapterId())) {
                dto.setChapterId(0L);
            }
            //校验并设置status
            this.checkUnPublishParamAndSettingAttribute(old, dto);

            List<CourseHomeworkEntity> homeworkEntityList = new ArrayList<>();
            CourseHomeworkEntity entity = courseHomeworkConvert.update(dto);

            entity.setClassId(old.getClassId());
            //添加当前作业
            this.addCurrentHomework(homeworkEntityList, entity);

            if (Objects.equals(YesNoNumberEnum.YES.getCode(), dto.getNowRelease())) {
                //同步发送到其他班级，和多轮次作业是叠加效果
                List<CourseHomeworkEntity> otherClassHomeworkList = this.addOtherClassHomework(dto.getStatus(), homeworkEntityList);
                if (CollectionUtils.isNotEmpty(otherClassHomeworkList)) {
                    homeworkEntityList.addAll(otherClassHomeworkList);
                }
            }

            //更新
            this.saveOrUpdateBatch(homeworkEntityList, 1500);

            // 立即发布,同步到学生的逻辑
            if (Objects.equals(YesNoNumberEnum.YES.getCode(), dto.getNowRelease())) {
                this.executeHomeworkList(dto.getStatus(), dto.getTaskType(), homeworkEntityList);
            }
        }

        return true;
    }

    /**
     * 未发布状态下，更新参数校验
     * 这里包含两种状态：1.定时发布，2.不定时发布，不定时发布又包含两种状态 A：立即发布，2：不发布
     *
     * @param dto
     */
    private void checkUnPublishParamAndSettingAttribute(CourseHomeworkEntity entity, CourseHomeworkUpdateDTO dto) {

        if (Objects.equals(HomeWorkTypeEnum.TASK_GROUP.getCode(), dto.getTaskType())) {
            //发布对象必须有
            CommonErrors.BAD_REQUEST.check(StringUtils.isNotEmpty(dto.getGroupIds()), MessageUtils.message("course.homework.select.publish.to"));
        }


        //作业轮数的判空
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), dto.getIsRepeat())) {
            CommonErrors.BAD_REQUEST.check(nonNull(dto.getRepeatDay()), MessageUtils.message("course.homework.times.is.not.blank"));
        }

        // 1定时发布
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), dto.getTiming())) {
            CommonErrors.BAD_REQUEST.check(nonNull(dto.getReleaseTime()), MessageUtils.message("course.content.select.releasetime"));
            CommonErrors.BAD_REQUEST.check(dto.getReleaseTime().isAfter(LocalDateTime.now()), MessageUtils.message("course.content.now.before.releasetime"));
            CommonErrors.BAD_REQUEST.check(dto.getEndTime().isAfter(dto.getReleaseTime()), MessageUtils.message("course.content.releasetime.before.endtime"));

            // 计算日期差异
            long daysDifference = ChronoUnit.DAYS.between(dto.getReleaseTime(), dto.getEndTime());
            CommonErrors.BAD_REQUEST.check(daysDifference >= dto.getRepeatDay(), "作业轮数必须小于作业期限");

            // 原作业为定时发布（修改前判断定时发布的作业是否已发布）
            if (Objects.equals(YesNoNumberEnum.YES.getCode(), entity.getTiming())) {
                if (Objects.nonNull(entity.getReleaseTime()) && entity.getReleaseTime().isBefore(LocalDateTime.now())) {
                    CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("course.homework.release.valid"));
                }
            }


            // 发布的时间赋值
            dto.setStatus(YesNoNumberEnum.NO.getCode());
            dto.setReleaseTime(dto.getReleaseTime());
            dto.setTiming(YesNoNumberEnum.YES.getCode());

            //不定时发布
        } else {
            // 计算日期差异
            if (dto.getRepeatDay() > 1) {
                long daysDifference = ChronoUnit.DAYS.between(LocalDateTime.now(), dto.getEndTime());
                CommonErrors.BAD_REQUEST.check(daysDifference >= dto.getRepeatDay(), "作业轮数必须小于作业期限");
            }

            //立即发布
            if (Objects.equals(YesNoNumberEnum.YES.getCode(), dto.getNowRelease())) {
                CommonErrors.BAD_REQUEST.check(dto.getEndTime().isAfter(LocalDateTime.now()), MessageUtils.message("course.content.releasetime.before.endtime"));
                dto.setStatus(YesNoNumberEnum.YES.getCode());
                dto.setReleaseTime(LocalDateTime.now());
            } else {
                CommonErrors.BAD_REQUEST.check(dto.getEndTime().isAfter(LocalDateTime.now()), MessageUtils.message("course.content.now.before.endtime"));
                dto.setStatus(YesNoNumberEnum.NO.getCode());
            }
        }
    }

    /**
     * 根据id集合删除 课程栏目作业数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteHomeworkByIds(List<Long> ids) {
        boolean flag = this.deletedByIds(ids);
        if (flag) {
            // 删除汇总内容中的作业
            courseContentClient.deleteCourseContentByIds(ids, CourseContentTypeEnum.HOMEWORK.getCode());
        }
        return flag;
    }

    /**
     * 根据id一键发布作业
     */
    @Override
    public boolean releaseHomework(CourseHomeworkReleaseDTO dto) {
        CourseHomeworkEntity entity = this.baseMapper.selectById(dto.getId());
        CommonErrors.BAD_REQUEST.check(entity.getEndTime().isAfter(LocalDateTime.now()), MessageUtils.message("course.content.now.before.endtime"));
        entity.setReleaseTime(LocalDateTime.now());
        entity.setStatus(YesNoNumberEnum.YES.getCode());
        this.baseMapper.updateById(entity);
        return this.executeHomeworkList(entity.getStatus(), entity.getTaskType(), new ArrayList<>(Collections.singletonList(entity)));
    }

    /**
     * 根据id一键发布作业 V2版本
     */
    @Override
    public boolean releaseHomeworkV2(CourseHomeworkReleaseDTO dto) {
        CourseHomeworkEntity entity = Optional.ofNullable(this.baseMapper.selectById(dto.getId()))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("course.homework.id.not.exit")));
        CommonErrors.BAD_REQUEST.check(Objects.equals(YesNoNumberEnum.NO.getCode(), entity.getStatus())
            , MessageUtils.message("course.homework.release.valid"));

        CommonErrors.BAD_REQUEST.check(entity.getEndTime().isAfter(LocalDateTime.now()), MessageUtils.message("course.content.now.before.endtime"));
        entity.setReleaseTime(LocalDateTime.now());
        entity.setTiming(YesNoNumberEnum.NO.getCode());
        entity.setStatus(YesNoNumberEnum.YES.getCode());
        this.baseMapper.updateById(entity);
        return this.executeHomeworkList(entity.getStatus(), entity.getTaskType(), new ArrayList<>(Collections.singletonList(entity)));
    }

    /**
     * 定时发布批量执行
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean homeworkTiming() {
        //查询定时未发布
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 每次只查询 1000条数据防止数据过大阻塞Mysql
        LambdaQueryWrapper<CourseHomeworkEntity> query = new LambdaQueryWrapper<>();
        query.eq(CourseHomeworkEntity::getTiming, YesNoNumberEnum.YES.getCode());
        query.eq(CourseHomeworkEntity::getStatus, YesNoNumberEnum.NO.getCode());
        query.le(CourseHomeworkEntity::getReleaseTime, fmt.format(LocalDateTime.now()));
        query.orderByDesc(CourseHomeworkEntity::getReleaseTime);
        query.last(" limit 500");
        List<CourseHomeworkEntity> singleClassHomeEntityList = this.baseMapper.selectList(query);

        if (singleClassHomeEntityList.size() > 0) {
            List<CourseHomeworkEntity> homeworkEntityList = new ArrayList<>();

            //添加当前作业（包含了当前的作业）
            singleClassHomeEntityList.forEach(single -> this.addCurrentHomework(homeworkEntityList, single));

            //添加其他班级作业
            singleClassHomeEntityList.forEach(l -> this.addOtherClassHomeworkEntityList(l, homeworkEntityList));

            if (CollectionUtils.isNotEmpty(homeworkEntityList)) {
                this.saveOrUpdateBatch(homeworkEntityList, 1500);
            }

            //筛选需要发布作业ID集合
            List<Long> ids = homeworkEntityList.stream().map(CourseHomeworkEntity::getId).collect(Collectors.toList());
            // 作业发布
            LambdaUpdateWrapper<CourseHomeworkEntity> wrapper = new LambdaUpdateWrapper<>();
            wrapper.set(CourseHomeworkEntity::getStatus, YesNoNumberEnum.YES.getCode()).in(CourseHomeworkEntity::getId, ids);
            boolean flag = this.update(wrapper);
            if (flag) {
                // 修改成功更新原数据 状态未已发布 1
                homeworkEntityList.forEach(item -> item.setStatus(YesNoNumberEnum.YES.getCode()));
                this.syncContentHomework(homeworkEntityList.stream().map(courseHomeworkConvert::convert).collect(Collectors.toList()));

                //分别执行小组作业和个人作业
                this.separateInitStudentLogBatch(homeworkEntityList);

            }

            // 根据 id 进行分组并去重，多轮次作业只发一次
            List<CourseHomeworkEntity> uniqueHomeworkList = new ArrayList<>(homeworkEntityList.stream().collect(Collectors.toMap(CourseHomeworkEntity::getId,
                    Function.identity(), (existing, replacement) -> existing)).values());
            //TODO 新奇助手推送
            Spring.committed(() -> uniqueHomeworkList.forEach(item -> assistantListen.releaseCourseContent(item.getId(), AssistantMessageTypeEnum.HOMEWORK)));
        }

        return true;
    }

    /**
     * 分别执行小组作业和个人作业
     *
     * @param homeworkEntityList 作业列表
     */
    @Transactional(rollbackFor = Exception.class)
    public void separateInitStudentLogBatch(List<CourseHomeworkEntity> homeworkEntityList) {
        Map<Integer, List<CourseHomeworkEntity>> homeworkListMap = homeworkEntityList.stream().collect(Collectors.groupingBy(CourseHomeworkEntity::getTaskType));
        List<CourseHomeworkEntity> classHomeworkList = homeworkListMap.get(HomeWorkTypeEnum.TASK_PERSONAL.getCode());
        List<CourseHomeworkEntity> groupHomeworkList = homeworkListMap.get(HomeWorkTypeEnum.TASK_GROUP.getCode());

        //批量同步班级作业
        if (CollectionUtils.isNotEmpty(classHomeworkList)) {
            this.initStudentLogBatch(classHomeworkList, YesNoNumberEnum.YES.getCode(), HomeWorkTypeEnum.TASK_PERSONAL.getCode());
        }

        //批量同步小组作业
        if (CollectionUtils.isNotEmpty(groupHomeworkList)) {
            this.initStudentLogBatch(groupHomeworkList, YesNoNumberEnum.YES.getCode(), HomeWorkTypeEnum.TASK_GROUP.getCode());
        }

    }

    /**
     * 作业提交未提交统计
     */
    @Override
    public AssistantTotalResultDTO selectHomeworkTakeTotal(Long contentId, Integer times) {
        return this.baseMapper.selectHomeworkTakeTotal(contentId, times);
    }

    /**
     * 作业提交未提交学生列表
     */
    @Override
    public List<StudentInfoResultDTO> selectHomeworkTakeStudent(Long contentId, Integer times, Integer status) {
        return this.baseMapper.selectHomeworkTakeStudent(contentId, times, status);
    }
}
